﻿using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;

namespace api2.AuthHelper.policys
{
    public class PermissionHandler : AuthorizationHandler<PermissionRequirement>
    {
        private readonly ILogger<PermissionHandler> _logger;
        private readonly IAuthenticationSchemeProvider _Schemes;

        public PermissionHandler(ILogger<PermissionHandler> logger, IAuthenticationSchemeProvider authenticationScheme)
        {
            _logger = logger;
            _Schemes = authenticationScheme;
        }
        protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
        {
            //从AuthorizationHandlerContext转成HttpContext，以便取出表求信息
            var filterContext = (context.Resource as Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext);
            //取出HttpContext上下文信息
            var httpContext = (context.Resource as Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext)?.HttpContext;
            if (httpContext != null)
            {
                var currentUserRoles = (from item in httpContext.User.Claims
                                        where item.Type == requirement.ClaimType
                                        select item.Value).ToList();
                var handlers = httpContext.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
                //需要到时候替换为service提供具体数据源
                requirement.Permissions = new List<PermissionItem>() { new PermissionItem() {Role="Admin",Url="" },
                    new PermissionItem() { Role="User",Url=""} };
                foreach (var scheme in await this._Schemes.GetRequestHandlerSchemesAsync())
                {
                    if (await handlers.GetHandlerAsync(httpContext, scheme.Name) is IAuthenticationRequestHandler handler && await handler.HandleRequestAsync())
                    {
                        //自定义异常返回数据
                        var payload = JsonConvert.SerializeObject(new { Code = "401", Message = "很抱歉，登录超时!请重新登录" });
                        httpContext.Response.StatusCode = StatusCodes.Status401Unauthorized;
                        filterContext.Result = new JsonResult(payload);
                        context.Succeed(requirement);
                        return;
                    }
                }
                var defaultAuthenticate = await _Schemes.GetDefaultAuthenticateSchemeAsync();
                if (defaultAuthenticate != null)
                {
                    var result = await httpContext.AuthenticateAsync(defaultAuthenticate.Name);
                    //判断是否登录    result?.Principal不为空即登录成功
                    if (result?.Principal != null)
                    {
                        httpContext.User = result.Principal;
                        if (true)
                        {
                            var currentRoles = (from item in httpContext.User.Claims
                                                where item.Type == requirement.ClaimType
                                                select item.Value).ToList();
                            var isMatchRole = false;
                            var permisssionRoles = requirement.Permissions.Where(x => currentRoles.Contains(x.Role.ToString())).ToList();//根据当前用户角色获取所有的角色信息
                            permisssionRoles.ForEach(x =>
                            {
                                try
                                {
                                    //if (Regex.Match(quesrUrl, x.Url.ToLower()).Value == quesrUrl)
                                    //{
                                    isMatchRole = true;//如果等于true 证明有权限
                                    //}
                                }
                                catch (Exception)
                                {

                                    throw;
                                }
                            });
                            if (currentRoles.Count <= 0 || !isMatchRole)
                            {
                                var payload = JsonConvert.SerializeObject(new { Code = "403", Message = "很抱歉，您无权访问该接口!请先分配权限" });
                                httpContext.Response.StatusCode = StatusCodes.Status403Forbidden;
                                filterContext.Result = new JsonResult(payload);
                                context.Succeed(requirement);
                                return;
                            }

                        }
                        //判断过期时间（这里仅仅是最坏验证原则，你可以不要这个if else的判断，因为我们使用的官方验证，Token过期后上边的result?.Principal 就为 null 了，进不到这里了，因此这里其实可以不用验证过期时间，只是做最后严谨判断）
                        if ((httpContext.User.Claims.SingleOrDefault(s => s.Type.Equals("exp", StringComparison.InvariantCultureIgnoreCase))?.Value) != null)
                        {
                            if (StampToDateTime(httpContext.User.Claims.SingleOrDefault(s => s.Type.Equals("exp", StringComparison.InvariantCultureIgnoreCase))?.Value) >= DateTime.Now)
                            {
                                context.Succeed(requirement);
                            }
                        }

                        else
                        {
                            //context.Fail();
                            //return;


                            //自定义返回数据
                            var payload = JsonConvert.SerializeObject(new { Code = "401", Message = "很抱歉，登录超时!请重新登录" });
                            httpContext.Response.StatusCode = StatusCodes.Status401Unauthorized;
                            filterContext.Result = new JsonResult(payload);
                            context.Succeed(requirement);
                            return;
                        }
                        return;
                    }
                    else
                    {
                        //自定义返回数据
                        var payload = JsonConvert.SerializeObject(new { Code = "401", Message = "很抱歉，登录超时!请重新登录" });
                        httpContext.Response.StatusCode = StatusCodes.Status401Unauthorized;
                        filterContext.Result = new JsonResult(payload);
                        context.Succeed(requirement);
                        return;
                    }
                }
            }

            context.Succeed(requirement);
        }

        /// <summary>
        /// 获取本地时间的世界时间戳
        /// </summary>
        /// <returns></returns>
        public long GetNowTimeStamp()
        {
            var TimeStamps = (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
            return TimeStamps;
        }
        /// <summary>
        /// 将时间转换为时间戳
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public long ToTimeStamp(DateTime dateTime)
        {
            var TimeStamps = (dateTime.Ticks - 621355968000000000) / 10000000;
            return TimeStamps;
        }
        /// <summary>
        /// 获取本地时间的世界时间的偏移量
        /// </summary>
        /// <returns></returns>
        public long GetUtcOffsets()
        {
            var UtcOffsets = TimeZone.CurrentTimeZone.GetUtcOffset(new DateTime()).Ticks / 10000;
            return UtcOffsets;
        }

        /// <summary>
        /// 将时间戳转换为时间
        /// </summary>
        /// <returns></returns>
        public DateTime ToDateTime(long TimeStamps)
        {
            var date = new DateTime(1970, 1, 1).AddMilliseconds(TimeStamps);
            //new DateTime().AddMilliseconds(621355968000000000/10000).AddMilliseconds(TimeStamps);//效果同上
            return date;
        }
        public  DateTime TransitionDateTime(double Timestamp)
        {
            TimeSpan timeSub = TimeSpan.FromMilliseconds(Timestamp);
            // DateTime.UnixEpoch对应的时间的时间戳为0
            return DateTime.UnixEpoch.Add(timeSub).AddHours(8);
        }
        public  DateTime StampToDateTime(string timeStamp)
        {
            DateTime dateTimeStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
            long lTime = long.Parse(timeStamp + "0000000");
            TimeSpan toNow = new TimeSpan(lTime);
            return dateTimeStart.Add(toNow);
        }
    }
}
